package com.ckerchina.admin.ckadmin.dao;

import java.io.Serializable;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;

import javax.persistence.EntityManager;
import javax.persistence.LockModeType;
import javax.persistence.PersistenceContext;
import javax.persistence.TypedQuery;

import com.ckerchina.admin.ckadmin.exception.ZhuziException;
import com.ckerchina.admin.ckadmin.utils.Page;

public abstract class AbstractDao<T extends Serializable, PK extends Serializable>  {
	@PersistenceContext
	protected EntityManager entityManager;
	
	protected EntityManager getEntityManager() {
		return entityManager;
	}

	private Class<T> entityClass; 
	public AbstractDao() {
		this.entityClass = null;
		Class<?> c = getClass();
		Type t = c.getGenericSuperclass();
		if (t instanceof ParameterizedType) {
			Type[] p = ((ParameterizedType) t).getActualTypeArguments();
			this.entityClass = (Class<T>) p[0];
		}
		if (this.entityClass == null) {
			throw new ZhuziException("类初始化失败");
		}
	}

	public T find(PK id) {
		if(id == null){
			return null;
		}
		return entityManager.find(entityClass, id);
	}
	
	public List<T> findAll() {
        return entityManager.createQuery("from " + this.entityClass.getName(), this.entityClass).getResultList();
    }
	
	public void persist(T t) {
		this.entityManager.persist(t);
	}

	public T merge(T t) {
		T merged = this.entityManager.merge(t);
		this.entityManager.flush();
		return merged;
	}
	

    public T lock(Long id){
        return entityManager.find(entityClass, id, LockModeType.PESSIMISTIC_WRITE);
    }
    
	public void remove(T t) {
		this.entityManager.remove(t);
	}
	
	
	public Page<T> findPage(String where, Map<String, Object> params, int start, int limit, String orderBy) {
		String sql = "SELECT o FROM " + this.entityClass.getName() + " o WHERE 1=1" + where + orderBy;
		TypedQuery<T> query = this.entityManager.createQuery(sql, this.entityClass);
		
		String countSql = "SELECT count(*) FROM " + this.entityClass.getName() + " o WHERE 1=1" + where;
		TypedQuery<Long> total = this.entityManager.createQuery(countSql, Long.class);
		
		for (Entry<String, Object> param : params.entrySet()) {
			query.setParameter(param.getKey(), param.getValue());
			total.setParameter(param.getKey(), param.getValue());
		}
		query.setFirstResult(start).setMaxResults(limit);
		return new Page<T>(query.getResultList(), total.getSingleResult());
	}
	
	public Page<T> findNativePage(String sql,String tableName,String where, Map<String, Object> params, int start, int limit, String orderBy) {
		 
		sql += " WHERE 1=1 " + where + orderBy;
		TypedQuery<T> query = this.entityManager.createQuery(sql, this.entityClass);
		
		String countSql = "SELECT count(*) FROM " + this.entityClass.getName() + " o WHERE 1=1" + where;
		TypedQuery<Long> total = this.entityManager.createQuery(countSql, Long.class);
		
		for (Entry<String, Object> param : params.entrySet()) {
			query.setParameter(param.getKey(), param.getValue());
			total.setParameter(param.getKey(), param.getValue());
		}
		query.setFirstResult(start).setMaxResults(limit);
		return new Page<T>(query.getResultList(), total.getSingleResult());
	}
}
